"""
Copyright (c) 2024 [Baijiankang/DUT]
简易火车订票系统

联系信息: [jiankang_bai@163.com]
项目地址: [https://gitee.com/BJKgitee/simple-train-ticket-booking-system]

保留所有权利。
"""

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkinter import simpledialog
from railway import Railway, load_data
import do_json
import ticket
import to_sql
import pandas as pd

# 加载数据
data = load_data("MergedTrainInfo_new.json")
railway = Railway(data)
root = tk.Tk()

# 显示结果的函数
def show_result_in_new_window(title, result):
    '''
        功能：
            在新窗口中显示查询结果
        参数：
            title: 窗口标题
            result: 查询结果
    '''
    new_window = tk.Toplevel(root)
    new_window.title(title)
    result_label = ttk.Label(new_window, text=result, justify="left", wraplength=380)
    result_label.pack(padx=10, pady=10, expand=True, fill="both")

# 查询最短路径的函数 ——— unused
def search_shortest_path(start, end, method):
    '''
        功能：
            查询最短路径
        参数：
            start: 始发站
            end: 终点站
            method: 查询方法
    '''
    try:
        if method == "distance":
            distance, path = railway.shortest_distance_path(start, end)
            result = f"最短距离: {distance}\n路径: {' -> '.join(path)}" if path else "没有找到路径"
            title = "最短距离查询结果"
        elif method == "time":
            time, path = railway.shortest_time_path(start, end)
            time_str = f"{time // 60}时{time % 60}分"
            result = f"所需时间: {time_str}\n路径: {' -> '.join(path)}" if path else "没有找到路径"
            title = "最佳路线查询结果"
        else:
            raise ValueError("无效的查询方法")
        show_result_in_new_window(title, result)
    except Exception as e:
        messagebox.showerror("错误", str(e))

# 查询最佳路径的函数
def auto_search_path(start, end):
    '''
        功能：
            自动查询合适路径
        参数：
            start: 始发站
            end: 终点站
    '''

    try:
        time, path, station, dire, train = railway.min_transfer_path_with_nonstop_check(start, end)  # 调用函数
        
        # 创建新窗口
        result_window = tk.Toplevel()
        result_window.title("查询结果")
        
        if path:
            # 显示花费时间
            time_str = f"{time // 60}时{time % 60}分"
            time_label = tk.Label(result_window, text=f"花费时间: {time_str}")
            time_label.pack()
            
            # 显示路径
            path_label = tk.Label(result_window, text="路径: ")
            path_label.pack()
            path_text = tk.Text(result_window, height=5, width=30)
            path_text.pack()
            path_text.insert(tk.END, "->".join(path))
            
            # 显示换乘站
            station_label = tk.Label(result_window, text=f"换乘站: {station}")
            station_label.pack()
            
            # 显示列车班次（下拉列表）
            train_combos = []
            for line in train:
                line_label = tk.Label(result_window, text=f"路段 {train.index(line) + 1}: ")
                line_label.pack()
                train_combo = ttk.Combobox(result_window, values=line)
                train_combo.pack()
                train_combos.append(train_combo)

            def check_tickets():
                min_tickets = float('inf')
                for i, combo in enumerate(train_combos):
                    selected_train = combo.get()
                    if i == 0:
                        start_station = start
                    else:
                        start_station = station[i-1]
                    if i == len(train_combos) - 1:
                        end_station = end
                    else:
                        end_station = station[i]
                    tickets = ticket.ticket_check('MergedTrainInfo_new.json', selected_train, start_station, end_station)
                    if tickets is not None:
                        min_tickets = min(min_tickets, tickets)

                messagebox.showinfo("余票查询结果", f"最少余票数: {min_tickets}")
                if min_tickets == 0:
                    messagebox.showwarning("余票查询结果", "该线路无余票")
                else:
                    if messagebox.askyesno("余票查询结果", f"是否购买 {selected_train} 列车 {start_station} -> {end_station} 的 {min_tickets} 张票?"):
                        # 购票逻辑
                        for i, combo in enumerate(train_combos):
                            selected_train = combo.get()
                            if i == 0:
                                start_station = start
                            else:
                                start_station = station[i-1]
                            if i == len(train_combos) - 1:
                                end_station = end
                            else:
                                end_station = station[i]
                            ticket.ticket_sale('MergedTrainInfo_new.json', selected_train, start_station, end_station)
                        messagebox.showinfo("购票成功", "请前往支付宝支付")

            check_button = tk.Button(result_window, text="查询余票", command=check_tickets)
            check_button.pack() 

        else:
            messagebox.showinfo("查询结果", "没有找到路径")
    except Exception as e:
        messagebox.showerror("错误", str(e))

# 管理员登录窗口类
class AdminLoginWindow:
    def __init__(self, root):
        '''
            功能：
                管理员登录窗口类
            参数：
                root: 父窗口
        '''
        self.root = root
        self.root.title("管理员登录")
        self.root.geometry("230x130")
        self.setup_ui()
        self.file_path = "MergedTrainInfo_new.json"

    def setup_ui(self):
        '''
            功能：
                管理员登录窗口界面布局
        '''
        self.username_label = ttk.Label(self.root, text="用户名:")
        self.username_label.grid(row=0, column=0, padx=10, pady=10, sticky="e")
        self.username_entry = ttk.Entry(self.root)
        self.username_entry.grid(row=0, column=1, padx=10, pady=10, sticky="w")

        self.password_label = ttk.Label(self.root, text="密码:")
        self.password_label.grid(row=1, column=0, padx=10, pady=10, sticky="e")
        self.password_entry = ttk.Entry(self.root, show="*")
        self.password_entry.grid(row=1, column=1, padx=10, pady=10, sticky="w")

        self.login_button = ttk.Button(self.root, text="登录", command=self.login)
        self.login_button.grid(row=2, column=0, columnspan=2, padx=10, pady=10, sticky="ew")
    
    def login(self):
        '''
            功能：
                管理员登录
        '''
        username = self.username_entry.get()
        password = self.password_entry.get()
        if username == "admin" and password == "123456":
            messagebox.showinfo("登录成功", "欢迎管理员")
            self.root.destroy()
            self.open_admin_window()
        else:
            messagebox.showerror("登录失败", "用户名或密码错误")

    def open_admin_window(self):
        '''
            功能：
                打开管理员界面
        '''
        admin_window = tk.Tk()
        admin_window.title("管理员界面")
        admin_window.geometry("230x280")
        self.setup_admin_ui(admin_window)

    def setup_admin_ui(self, admin_window):
        '''
            功能：
                管理员界面布局  
            参数：
                admin_window: 管理员窗口
        '''
        ttk.Label(admin_window, text="请输入要处理的始发站和终点站:").grid(row=0, column=0, columnspan=2, padx=10, pady=10)
        start_label = ttk.Label(admin_window, text="始发站:")
        start_label.grid(row=1, column=0, padx=10, pady=10, sticky="e")
        start_entry = ttk.Entry(admin_window)
        start_entry.grid(row=1, column=1, padx=10, pady=10, sticky="w")

        end_label = ttk.Label(admin_window, text="终点站:")
        end_label.grid(row=2, column=0, padx=10, pady=10, sticky="e")
        end_entry = ttk.Entry(admin_window)
        end_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w")

        modify_route_button = ttk.Button(admin_window, text="修改线路", command=lambda: self.change_route_data(start_entry.get(), end_entry.get()))
        modify_route_button.grid(row=3, column=1, padx=10, pady=10, columnspan=2, sticky="ew")

        modify_schedule_button = ttk.Button(admin_window, text="修改班次", command=lambda: self.modify_schedule(start_entry.get(), end_entry.get()))
        modify_schedule_button.grid(row=4, column=1, padx=10, pady=10, columnspan=2, sticky="ew")

        modify_station_button = ttk.Button(admin_window, text="更新数据库数据", command=lambda: self.updata_station_data())
        modify_station_button.grid(row=5, column=1, padx=10, pady=10, columnspan=2, sticky="ew")

    def updata_station_data(self):
        '''
            功能：
                更新数据库数据
        '''
        print("正在更新数据库数据...") # ********************************************************待实现********************************
        df = pd.read_json('MergedTrainInfo_new.json')
        df.to_csv('data.csv', encoding='utf-8', index=False)
        csv_path1 = r'data.csv'  # 转入csv文件
        to_sql.csv_to_sql(csv_path1)
        messagebox.showinfo("提示", "更新成功！")
    
    def change_route_data(self, start, end):
        '''
            功能：
                修改线路数据
            参数：
                start: 始发站
                end: 终点站
        '''
        def on_rewrite():
            '''
                功能：
                    重写线路数据
            '''
            messagebox.showinfo("提示", f"你选择了重写线路 {start} -> {end}")
            self.modify_route(start, end)

        def on_add_station():
            '''
                功能：
                    添加车站
            '''
            popup = tk.Toplevel()
            popup.title("添加站点")
            self.setup_add_station_ui(popup, start, end)

        def on_remove_station():
            '''
                功能：
                    删除车站
            '''
            popup = tk.Toplevel()
            popup.title("删除站点")
            self.setup_remove_station_ui(popup, start, end)

        def on_view_schedules():
            '''
                功能：
                    查看同一条线路的所有数据
            '''
            route_data = do_json.query_data_from_json(self.file_path, start, end)
            if route_data:
                # 格式化所有数据
                formatted_data = f"始发站: {route_data['start_s']}\n" \
                                f"终点站: {route_data['end_s']}\n" \
                                f"类型: {route_data['type']}\n" \
                                f"距离: {route_data['distance']}\n" \
                                f"时间: {route_data['time']}\n" \
                                f"站点: {route_data['stations']}\n" \
                                f"正向车次: {route_data['forward']}\n" \
                                f"反向车次: {route_data['backward']}"
                show_result_in_new_window("线路信息", formatted_data)
            else:
                messagebox.showerror("错误", "没有找到线路信息")


        root = tk.Tk()
        root.title("修改线路数据")
        root.geometry("250x120")
        tk.Button(root, text="重写线路", command=on_rewrite).pack(fill=tk.X)
        tk.Button(root, text="添加站点", command=on_add_station).pack(fill=tk.X)
        tk.Button(root, text="删除站点", command=on_remove_station).pack(fill=tk.X)
        tk.Button(root, text="查看线路", command=on_view_schedules).pack(fill=tk.X)
        root.mainloop()

    def setup_add_station_ui(self, popup, start, end):
        '''
            功能：
                添加车站界面布局
            参数：
                popup: 弹出窗口
                start: 始发站
        '''
        tk.Label(popup, text="要将车站添加到哪个位置:").grid(row=0, column=0)
        station_add_position_entry = tk.Entry(popup)
        station_add_position_entry.grid(row=0, column=1)

        tk.Label(popup, text="要添加的车站:").grid(row=1, column=0)
        station_to_add_entry = tk.Entry(popup)
        station_to_add_entry.grid(row=1, column=1)

        tk.Label(popup, text="与前站的距离:").grid(row=2, column=0)
        distance_to_add_entry = tk.Entry(popup)
        distance_to_add_entry.grid(row=2, column=1)

        tk.Label(popup, text="与前站的时间:").grid(row=3, column=0)
        time_to_add_entry = tk.Entry(popup)
        time_to_add_entry.grid(row=3, column=1)

        def on_submit():
            station_add_position = int(station_add_position_entry.get())
            station_to_add = station_to_add_entry.get()
            distance_to_add = int(distance_to_add_entry.get())
            time_to_add = int(time_to_add_entry.get())

            if not station_add_position or not station_to_add or not distance_to_add or not time_to_add:
                messagebox.showerror("错误", "所有字段都必须填写")
                return

            try:
                distance_to_add = float(distance_to_add)
                time_to_add = float(time_to_add)
            except ValueError:
                messagebox.showerror("错误", "距离和时间必须是数字")
                return

            do_json.add_station_to_json(self.file_path, start, end, station_add_position, station_to_add, int(distance_to_add), int(time_to_add))
            messagebox.showinfo("提示", "添加成功！")
            popup.destroy()

        submit_button = tk.Button(popup, text="提交", command=on_submit)
        submit_button.grid(row=4, column=0, columnspan=2)

    def setup_remove_station_ui(self, popup, start, end):
        '''
            功能：
                删除车站界面布局
            参数：
                popup: 弹出窗口
                start: 始发站
        '''
        tk.Label(popup, text="要删除的车站:").grid(row=0, column=0)
        station_to_remove_entry = tk.Entry(popup)
        station_to_remove_entry.grid(row=0, column=1)

        def on_submit():
            station_to_remove = station_to_remove_entry.get()

            if not station_to_remove:
                messagebox.showerror("错误", "所有字段都必须填写")
                return

            do_json.remove_station_from_json(self.file_path, start, end, station_to_remove)
            messagebox.showinfo("提示", "删除成功！")
            popup.destroy()

        submit_button = tk.Button(popup, text="提交", command=on_submit)
        submit_button.grid(row=1, column=0, columnspan=2)

    def modify_schedule(self, start, end):
        '''
            功能：
                修改班次数据
            参数：
                start: 始发站
                end: 终点站
        '''
        messagebox.showinfo("提示", f"你正在修改班次数据: {start} -> {end}")
        schedules = railway.get_schedules(start, end)
        if not schedules:
            schedules = railway.get_schedules(end, start)  # 尝试反向查询
        if schedules:
            self.open_schedule_modify_window(schedules)
        else:
            messagebox.showerror("错误", "没有找到班次信息")

    def open_schedule_modify_window(self, schedules):
        '''
            功能：
                打开修改班次窗口
            参数：
                schedules: 班次列表
        '''
        modify_window = tk.Toplevel()
        modify_window.title("修改班次")
        modify_window.geometry("300x200")
        schedule_label = ttk.Label(modify_window, text="选择要修改的班次:")
        schedule_label.pack(pady=10)
        schedule_var = tk.StringVar(modify_window)
        schedule_var.set(schedules[0])
        schedule_option = ttk.OptionMenu(modify_window, schedule_var, *schedules)
        schedule_option.pack(pady=10)
        modify_button = ttk.Button(modify_window, text="修改", command=lambda: self.modify_selected_schedule(schedule_var.get()))
        modify_button.pack(pady=10)

    def modify_selected_schedule(self, schedule):
        '''
            功能：
                修改选中的班次数据
            参数：
                schedule: 要修改的班次
        '''
        print("你正在修改班次...")
        # 弹出输入框
        input_tickets = simpledialog.askstring("输入票数", "请输入票数，用英文逗号隔开：")

        # 将输入的票数以逗号分隔后转换成列表
        list_of_tickets = input_tickets.split(',')

        do_json.change_schedule(self.file_path, schedule, list_of_tickets)
        messagebox.showinfo("提示", "修改成功！")
        # ********************************************************************** 待添加 *********

    def modify_route(self, start, end):
        '''
            功能：
                修改线路数据
            参数：
                start: 始发站
                end: 终点站
        '''
        messagebox.showinfo("提示", f"你正在修改线路: {start} -> {end}")
        new_data = self.get_new_route_data(start, end)
        do_json.modify_json_file(self.file_path, new_data, start, end)
        messagebox.showinfo("提示", "修改成功！")

    def get_new_route_data(self, start, end):
        '''
            功能：
                获取新的线路数据
            参数：
                start: 始发站
                end: 终点站
        '''
        new_data = {}

        def submit(new_data):
            if not type_entry.get() or not distance_entry.get() or not time_entry.get() or not stations_entry.get() or not forward_entry.get() or not backward_entry.get():
                messagebox.showwarning("警告", "所有字段都必须填写")
                return

            stations = stations_entry.get().split(",")
            num_stations = len(stations)

            forward_trains = forward_entry.get().split(",")
            backward_trains = backward_entry.get().split(",")

            forward_tickets = {train: [0] + [20] * (num_stations - 1) for train in forward_trains}
            backward_tickets = {train: [20] * (num_stations - 1) + [0] for train in backward_trains}

            new_data.update({
                "start_s": start,
                "end_s": end,
                "type": type_entry.get(),
                "distance": list(map(int, distance_entry.get().split(","))),
                "time": list(map(int, time_entry.get().split(","))),
                "stations": stations,
                "forward": forward_tickets,
                "backward": backward_tickets
            })
            top.destroy()

        top = tk.Toplevel()
        top.title("输入新的线路数据")
        top.geometry("360x310")

        ttk.Label(top, text="始发站:").grid(row=0, column=0, padx=10, pady=5)
        ttk.Label(top, text=start).grid(row=0, column=1, padx=10, pady=5)

        ttk.Label(top, text="终点站:").grid(row=1, column=0, padx=10, pady=5)
        ttk.Label(top, text=end).grid(row=1, column=1, padx=10, pady=5)

        ttk.Label(top, text="列车类型:").grid(row=2, column=0, padx=10, pady=5)
        type_entry = ttk.Entry(top)
        type_entry.grid(row=2, column=1, padx=10, pady=5)

        ttk.Label(top, text="距离列表（用逗号分隔）:").grid(row=3, column=0, padx=10, pady=5)
        distance_entry = ttk.Entry(top)
        distance_entry.grid(row=3, column=1, padx=10, pady=5)

        ttk.Label(top, text="时间列表（用逗号分隔）:").grid(row=4, column=0, padx=10, pady=5)
        time_entry = ttk.Entry(top)
        time_entry.grid(row=4, column=1, padx=10, pady=5)

        ttk.Label(top, text="经停站列表（用逗号分隔）:").grid(row=5, column=0, padx=10, pady=5)
        stations_entry = ttk.Entry(top)
        stations_entry.grid(row=5, column=1, padx=10, pady=5)

        ttk.Label(top, text="正向车次列表（用逗号分隔）:").grid(row=6, column=0, padx=10, pady=5)
        forward_entry = ttk.Entry(top)
        forward_entry.grid(row=6, column=1, padx=10, pady=5)

        ttk.Label(top, text="反向车次列表（用逗号分隔）:").grid(row=7, column=0, padx=10, pady=5)
        backward_entry = ttk.Entry(top)
        backward_entry.grid(row=7, column=1, padx=10, pady=5)

        ttk.Button(top, text="提交", command=lambda: submit(new_data)).grid(row=8, column=0, columnspan=2, padx=10, pady=10)

        top.wait_window(top)
        return new_data

# 打开查询窗口的函数
def open_query_window(parent):
    '''
        功能：
            打开查询窗口
        参数：
            parent: 父窗口
    '''
    query_window = tk.Toplevel(parent)
    query_window.title("查询车票")
    query_window.geometry("220x140")
    start_label = ttk.Label(query_window, text="起点:")
    start_label.grid(row=0, column=0, padx=10, pady=10, sticky="e")
    start_entry = ttk.Entry(query_window)
    start_entry.grid(row=0, column=1, padx=10, pady=10, sticky="w")

    end_label = ttk.Label(query_window, text="终点:")
    end_label.grid(row=1, column=0, padx=10, pady=10, sticky="e")
    end_entry = ttk.Entry(query_window)
    end_entry.grid(row=1, column=1, padx=10, pady=10, sticky="w")

    time_button = ttk.Button(query_window, text="查询最佳路线", command=lambda: auto_search_path(start_entry.get(), end_entry.get()))
    time_button.grid(row=2, column=0, padx=10, pady=10, columnspan=2, sticky="ew")

# 打开管理员登录窗口的函数
def open_admin_login_window():
    '''
        功能：
            打开管理员登录窗口
    '''
    admin_login_root = tk.Tk()
    AdminLoginWindow(admin_login_root)
    admin_login_root.mainloop()

# 显示所有线路信息的函数
def show_all_routes():
    '''
        功能：
            显示所有线路信息
    '''
    routes = railway.get_all_routes()
    route_info = "\n".join([f"{start} -> {end}: 距离 {distance} km, 时间 {time // 60}时{time % 60}分" for start, end, distance, time in routes])
    show_result_in_new_window("所有线路", route_info)

# 主函数
def main():
    # 设置窗口标题和大小
    root.title("火车订票系统")
    root.geometry("600x500")
    
    # 设置样式主题
    style = ttk.Style()
    style.theme_use('clam')
    
    # 加载并显示图片
    image = tk.PhotoImage(file="south_door.png")
    image_label = ttk.Label(root, image=image)
    image_label.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky="nsew")
    
    # 创建并放置游客登录按钮
    guest_button = ttk.Button(root, text="游客登录", command=lambda: open_query_window(root))
    guest_button.grid(row=1, column=0, padx=10, pady=10, sticky="ew")
    
    # 创建并放置管理员登录按钮
    admin_button = ttk.Button(root, text="管理员登录", command=open_admin_login_window)
    admin_button.grid(row=1, column=1, padx=10, pady=10, sticky="ew")
    
    # 配置网格列和行的权重
    root.grid_columnconfigure(0, weight=1)
    root.grid_columnconfigure(1, weight=1) 
    root.grid_rowconfigure(0, weight=1) 
    root.grid_rowconfigure(1, weight=1)
    
    # 启动主循环
    root.mainloop()

if __name__ == "__main__":
   main()    
   # pass